package com.lookme.lmtool.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.jhlabs.image.ScaleFilter;
import com.lookme.core.javafx.FxApp;
import com.lookme.core.javafx.dialog.FxAlerts;
import com.lookme.lmtool.utils.JexlUtils;
import com.lookme.lmtool.cracker.*;
import com.lookme.lmtool.cracker.filter.IFilter;
import com.lookme.lmtool.cracker.spliter.ISpliter;
import com.lookme.lmtool.model.Rect;
import com.lookme.lmtool.model.SpliterInfo;
import com.lookme.lmtool.model.CharAspect;
import com.lookme.lmtool.model.ItemInfo;
import com.lookme.lmtool.utils.ImageUtils;
import com.lookme.lmtool.utils.ToolUtils;
import com.lookme.lmtool.view.*;
import javafx.application.Platform;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.geometry.Pos;
import javafx.geometry.Side;
import javafx.scene.control.*;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.*;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.util.Callback;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
;

import javax.imageio.ImageIO;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
import java.util.List;

public class CaptchaCrackerController extends CaptchaCrackerView {
    MainController mainController;

    @Getter
    ItemInfo itemInfo;

    File initImageDirectory=null;

    FilterMenu filterMenu=null;

    BufferedImage sourceImage =null;
    BufferedImage targetImage =null;

    BufferedImage previewImage1=null;
    BufferedImage previewImage2=null;
    List<SpliterInfo> splitInfos;

    CodeWebView downImageScriptCode=null;

    CodeWebView ocrScriptCode=null;

    Thread threadDrawLine;

    float scale=4;
    boolean mustExit=false;

    DecimalFormat decimalFormat=new DecimalFormat("0.00");

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        initView();
        initEvent();
    }

    public void destroy(){
        this.mustExit=true;
    }

    public void init(MainController mainController, ItemInfo itemInfo) {
        this.mainController=mainController;
        this.itemInfo=itemInfo;
        if(this.itemInfo.getFilterList()!=null) {
            this.tableFilter.setItems(FXCollections.observableArrayList(this.itemInfo.getFilterList()));
        }
        String url=this.itemInfo.getUrl();
        if(StringUtils.isNotEmpty(url)) {
            this.txtFilePath.setText(url);
            if(url.startsWith("http")){
                loadUrlImage(url);
            }else{
                loadFileImage(new File(url));
            }
        }

        List<ISpliter> spliterList=ObjectUtil.cloneByStream(CrackerFactory.SUPPORT_SPLITER_LIST);
        cbSpliter.setItems(FXCollections.observableArrayList(spliterList));

        if(itemInfo.getSpliter()!=null){
            for(ISpliter spliter:spliterList) {
                if(spliter.getClass().equals(itemInfo.getSpliter().getClass())) {
                    BeanUtil.copyProperties(itemInfo.getSpliter(),spliter);
                    cbSpliter.getSelectionModel().select(spliter);
                    break;
                }
            }
        }

        if(this.itemInfo.getCharAspectList()!=null){
            tableFeatureLib.setItems(FXCollections.observableArrayList(this.itemInfo.getCharAspectList()));
        }

        if(this.itemInfo.getDownScript()==null){
            this.itemInfo.setDownScript(getDefaultDownScript());

        }else{
            String script=this.itemInfo.getDownScript();
            downImageScriptCode.setScript(script);
        }
        if(this.itemInfo.getOcrScript()==null){
            this.itemInfo.setOcrScript(getDefaultOcrScript());
        }else{
            String script=this.itemInfo.getOcrScript();

            ocrScriptCode.setScript(script);
        }



    }

    public String formatMilliseconds(long milliseconds){
        if(milliseconds>=1000){
            return decimalFormat.format(milliseconds/1000)+"秒";
        }else{
            return milliseconds+"毫秒";
        }
    }


    private void initView() {
        filterMenu=new FilterMenu(new Callback<IFilter, Void>() {
            @Override
            public Void call(IFilter param) {
                IFilter filter=ObjectUtil.cloneByStream(param);
                itemInfo.addFilter(filter);
                tableFilter.getItems().add(filter);
                processImage();
                return null;
            }
        });

        btnExportFeatureLib.setGraphic(ToolUtils.getButtonGraphics("/images/export2.png"));
        btnImportFeatureLib.setGraphic(ToolUtils.getButtonGraphics("/images/import.png"));
        btnLoad.setGraphic(ToolUtils.getButtonGraphics("/images/load.png"));
        btnReOcr.setGraphic(ToolUtils.getButtonGraphics("/images/ocrimg.png"));
        btnClearFeatureLib.setGraphic(ToolUtils.getButtonGraphics("/images/clear.png"));

        colFilterName.setCellValueFactory(new PropertyValueFactory<>("name"));
        colFilterSelect.setCellValueFactory(new PropertyValueFactory<>("selected"));
        colFilterParam.setCellValueFactory(new PropertyValueFactory<>("name"));
        colFilterPreviewImage.setCellValueFactory(new PropertyValueFactory<>("image"));

        tab1.setGraphic(ToolUtils.getButtonGraphics("/images/img.png"));
        tab2.setGraphic(ToolUtils.getButtonGraphics("/images/xin.png"));
        tab3.setGraphic(ToolUtils.getButtonGraphics("/images/download.png"));
        tab4.setGraphic(ToolUtils.getButtonGraphics("/images/ocrs.png"));



        colFilterPreviewImage.setCellFactory(new Callback<TableColumn<IFilter, BufferedImage>, TableCell<IFilter, BufferedImage>>() {
            @Override
            public TableCell<IFilter, BufferedImage> call(TableColumn<IFilter, BufferedImage> param) {
                return new TableCellWithImage<>(20);
            }
        });
        colFilterName.setCellFactory(new Callback<TableColumn<IFilter, String>, TableCell<IFilter, String>>() {
            @Override
            public TableCell<IFilter, String> call(TableColumn<IFilter, String> param) {
                TableCell<IFilter, String> cell = new TableCell<IFilter, String>(){
                    @Override
                    public void updateItem(String item, boolean empty)
                    {
                        if(item != null)
                        {
                            int row=getIndex();
                            IFilter filter=tableFilter.getItems().get(row);
                            setGraphic(new Label(item));
                            if(filter.isSelected()) {
                                long costTime = filter.getCostTime();
                                if(costTime<100){
                                    setTextFill(javafx.scene.paint.Color.DARKGREEN);
                                }else if(costTime<500){
                                    setTextFill(javafx.scene.paint.Color.YELLOWGREEN);
                                }else {
                                    setTextFill(javafx.scene.paint.Color.DARKRED);
                                }
                                setText("("+formatMilliseconds(costTime)+")");
                            }

                        }
                    }
                };
                cell.setAlignment(Pos.CENTER);
                return cell;
            }
        });

        colFilterParam.setCellFactory(new Callback<TableColumn<IFilter, String>, TableCell<IFilter, String>>() {
            @Override
            public TableCell<IFilter, String> call(TableColumn<IFilter, String> param) {
                TableCell<IFilter, String> cell = new TableCell<IFilter, String>(){
                    @Override
                    public void updateItem(String item, boolean empty)
                    {
                        if(item != null)
                        {
                           String text="";
                           int row=getIndex();
                           text=tableFilter.getItems().get(row).toString();
                            setTooltip(new Tooltip(text));
                           setText(text);
                        }
                    }
                };
                cell.setAlignment(Pos.CENTER);
                return cell;
            }
        });


        colFilterSelect.setCellFactory(
                CellFactory.tableCheckBoxColumn(new Callback<Integer, ObservableValue<Boolean>>() {
                    @Override
                    public ObservableValue<Boolean> call(Integer index) {
                        final IFilter g = (IFilter) tableFilter.getItems().get(index);
                        ObservableValue<Boolean> ret =
                                new SimpleBooleanProperty(g, "selected", g.isSelected());
                        ret.addListener(new ChangeListener<Boolean>() {
                            @Override
                            public void changed(
                                    ObservableValue<? extends Boolean> observable,
                                    Boolean oldValue, Boolean newValue) {
                                g.setSelected(newValue);
                                processImage();
                            }
                        });
                        return ret;
                    }
                }));





        paneSpliterParam.prefWidthProperty().bind(paneSpliter.widthProperty().add(-200));
        chkShowSplitLine.disableProperty().bind(chkShowOcrResult.selectedProperty().not());


        colCharIndex.setCellValueFactory(new PropertyValueFactory<>("key"));
        colCharName.setCellValueFactory(new PropertyValueFactory<>("key"));
        colCharSize.setCellValueFactory(new PropertyValueFactory<>("width"));
        colCharFeature.setCellValueFactory(new PropertyValueFactory<>("value"));
        colCharImage.setCellValueFactory(new PropertyValueFactory<>("image"));
        colOpt.setCellValueFactory(new PropertyValueFactory<>("key"));


        colCharName.setCellFactory(new Callback<TableColumn<CharAspect, String>, TableCell<CharAspect, String>>() {
            @Override
            public TableCell<CharAspect, String> call(TableColumn<CharAspect, String> param) {
                TableCell<CharAspect, String> cell = new TableCell<CharAspect, String>(){
                    @Override
                    public void updateItem(String item, boolean empty)
                    {
                        if(item != null)
                        {
                            setText(item);
                        }
                    }
                };
                cell.setAlignment(Pos.CENTER);
                return cell;
            }
        });
        colCharIndex.setCellFactory(new Callback<TableColumn<CharAspect, String>, TableCell<CharAspect, String>>() {
            @Override
            public TableCell<CharAspect, String> call(TableColumn<CharAspect, String> param) {
                TableCell<CharAspect, String> cell = new TableCell<CharAspect, String>(){
                    @Override
                    public void updateItem(String item, boolean empty)
                    {
                        int rowIndex=getIndex();
                        if(item != null)
                        {
                            setText(""+(rowIndex+1));
                        }
                    }
                };
                cell.setAlignment(Pos.CENTER);
                return cell;
            }
        });
        colCharSize.setCellFactory(new Callback<TableColumn<CharAspect, Integer>, TableCell<CharAspect, Integer>>() {
            @Override
            public TableCell<CharAspect, Integer> call(TableColumn<CharAspect, Integer> param) {
                TableCell<CharAspect, Integer> cell = new TableCell<CharAspect, Integer>(){
                    @Override
                    public void updateItem(Integer item, boolean empty)
                    {
                        if(item != null)
                        {
                            setText(""+item);
                        }
                    }
                };
                cell.setAlignment(Pos.CENTER);
                return cell;
            }
        });

        colCharImage.setCellFactory(new Callback<TableColumn<CharAspect, BufferedImage>, TableCell<CharAspect, BufferedImage>>() {
            @Override
            public TableCell<CharAspect, BufferedImage> call(TableColumn<CharAspect, BufferedImage> param) {
                return new TableCellWithImage<>(20);
            }
        });

        colOpt.setCellFactory(new Callback<TableColumn<CharAspect, String>, TableCell<CharAspect, String>>() {
            @Override
            public TableCell<CharAspect, String> call(TableColumn<CharAspect, String> param) {
                TableCell<CharAspect, String> cell = new TableCell<CharAspect, String>(){
                    @Override
                    public void updateItem(String item, boolean empty)
                    {
                        Hyperlink hyperlink = (Hyperlink) getGraphic();
                        if(hyperlink==null){
                            hyperlink=new Hyperlink("删除");
                            int index=getIndex();
                            hyperlink.setOnAction(new EventHandler<ActionEvent>() {
                                @Override
                                public void handle(ActionEvent event) {
                                    itemInfo.getCharAspectList().remove(index);
                                    tableFeatureLib.getItems().remove(index);
                                    tableFeatureLib.refresh();
                                }
                            });
                        }
                        if(item != null)
                        {
                            setGraphic(hyperlink);
                        }
                    }
                };
                cell.setAlignment(Pos.CENTER);
                return cell;
            }
        });

        downImageScriptCode=new CodeWebView(webViewDownScript, getDefaultDownScript(), new Callback<String, Void>() {
            @Override
            public Void call(String param) {
                itemInfo.setDownScript(param);
                processImage();
                return null;
            }
        });

        ocrScriptCode=new CodeWebView(webViewOcrScript, getDefaultOcrScript(), new Callback<String, Void>() {
            @Override
            public Void call(String param){
                itemInfo.setOcrScript(param);
                processImage();
                return null;
            }
        });

        threadDrawLine=new Thread(new Runnable() {
            @Override
            public void run() {
                while(!mustExit){
                    if(previewImage1!=null) {
                        if (chkShowOcrResult.isSelected() && chkShowSplitLine.isSelected()) {
                            previewImage2 = drawSplitLine();
                        } else {
                            previewImage2 = ImageUtils.copyImage(previewImage1);
                        }
                        Platform.runLater(new Runnable() {
                            @Override
                            public void run() {
                                showPreviewImage();
                            }
                        });
                    }
                    try {
                        Thread.sleep(300);
                    } catch (InterruptedException e) {
                    }
                }
            }
        });
        threadDrawLine.start();
    }


    public void initEvent() {
        paneLeft.heightProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                if(oldValue.intValue()>0) {
                    paneFilter.setPrefHeight(paneFilter.getPrefHeight() + newValue.floatValue() - oldValue.floatValue());
                    paneFilterParamContainer.setPrefHeight(paneFilterParamContainer.getPrefHeight() + newValue.floatValue() - oldValue.floatValue());
                    paneSourceImg.setPrefHeight(paneSourceImg.getPrefHeight() + newValue.floatValue() - oldValue.floatValue());
                }
            }
        });

        tableFilter.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<IFilter>() {
            @Override
            public void changed(ObservableValue<? extends IFilter> observable, IFilter oldValue, IFilter newValue) {
                if(newValue!=null) {
                    CrackerEditor.createParamEditor(paneFilterParam,newValue,new Callback<ICracker, Void>(){
                        @Override
                        public Void call(ICracker param) {
                            processImage();
                            return null;
                        }
                    });

                    if(newValue.getImage()!=null) {
                        lblFilterImgInfo.setText(newValue.getImage().getWidth()+" * "+newValue.getImage().getHeight());
                    }else{
                        lblFilterImgInfo.setText("");
                    }
                }
            }
        });

        cbSpliter.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<ISpliter>() {
            @Override
            public void changed(ObservableValue<? extends ISpliter> observable, ISpliter oldValue, ISpliter newValue) {
                if(newValue!=null){
                    itemInfo.setSpliter(newValue);
                    CrackerEditor.createParamEditor(paneSpliterParam,itemInfo.getSpliter(), new Callback<ICracker, Void>() {
                        @Override
                        public Void call(ICracker param) {
                             processImage();
                            return null;
                        }
                    });
                    processImage();
                }
            }
        });

        chkShowGrid.selectedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                processImage();
            }
        });

        chkShowSplitLine.selectedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                processImage();
            }
        });

        chkShowOcrResult.selectedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                paneOcrResult.setVisible(newValue);
                if(newValue){
                    AnchorPane.setBottomAnchor(panePreview,200d);
                }else{
                    AnchorPane.setBottomAnchor(panePreview,0d);
                }
                processImage();
            }
        });

        imgPreview.setOnMouseMoved(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                int x=(int)event.getX(),y=(int)event.getY();
                if(targetImage!=null&&x<targetImage.getWidth()&&y<targetImage.getHeight()) {
                    int color = targetImage.getRGB(x, y);
                    int r = ((color >> 16) & 0xff);
                    int g = ((color >> 8) & 0xff);
                    int b = ((color) & 0xff);
                    lblPreviewInfo.setText("x:" + x / scale + " y:" + y / scale + "  color:#" + ImageUtils.awtColorToHexValue(ImageUtils.intToAwtColor(color)).substring(2) + " r:" + r + " g:" + g + " b:" + b);
                }
            }
        });
        imgPreview.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                ClipboardContent content=new ClipboardContent();
                content.put(DataFormat.PLAIN_TEXT,lblPreviewInfo.getText());
                Clipboard.getSystemClipboard().setContent(content);
            }
        });
        imgPreview.setOnMouseExited(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                lblPreviewInfo.setText("");
            }
        });

        tableFilter.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<IFilter>() {
            @Override
            public void changed(ObservableValue<? extends IFilter> observable, IFilter oldValue, IFilter newValue) {
                if(newValue!=null&&newValue.getImage()!=null) {
                        lblFilterImgInfo.setText(newValue.getImage().getWidth()+" * "+newValue.getImage().getHeight());
                    }else{
                        lblFilterImgInfo.setText("");
                    }
            }
        });
    }

    @Override
    protected void finalize() throws Throwable {

    }


    @FXML
    void handlerAddFilter(ActionEvent event) {
       filterMenu.show(btnAddFilter, Side.BOTTOM,0,0);
    }

    @FXML
    void handlerBrowser(ActionEvent event) {

        if(initImageDirectory==null){
            initImageDirectory= FileSystemView.getFileSystemView().getHomeDirectory();;
        }
        File file = ToolUtils.chooseFile(initImageDirectory,new FileChooser.ExtensionFilter("All Images", "*.*"),
                new FileChooser.ExtensionFilter("JPG", "*.jpg"), new FileChooser.ExtensionFilter("PNG", "*.png"),
                new FileChooser.ExtensionFilter("gif", "*.gif"), new FileChooser.ExtensionFilter("jpeg", "*.jpeg"),
                new FileChooser.ExtensionFilter("bmp", "*.bmp"));
        if (file != null) {
            loadFileImage(file);
        }
    }

    public void loadFileImage(File file){
        Image image = null;
        try {

            sourceImage =ImageIO.read(file);
            image=SwingFXUtils.toFXImage(sourceImage, null);
            imgSource.setImage(image);
            txtFilePath.setText(file.getAbsolutePath());
            initImageDirectory=file.getParentFile();
            itemInfo.setUrl(file.getAbsolutePath());

            processImage();
        } catch (IOException e) {
        }
    }
    public void loadUrlImage(String url){
        btnLoad.setDisable(true);
        new Thread(new Runnable() {
            @Override
            public void run() {
                Map<String, Object> params = new HashMap<>();
                params.put("url",url);
                params.put("controller",this);
                params.put("HttpUtil",HttpUtil.class);
                params.put("HttpRequest",HttpRequest.class);
                params.put("HttpResponse",HttpResponse.class);
                params.put("JSON", JSON.class);
                params.put("BufferedImage",BufferedImage.class);
                params.put("ImageIO",ImageIO.class);
                params.put("sout",System.out);
                params.put("ImageUtils",ImageUtils.class);
                Image image = null;
                try {
                    sourceImage = JexlUtils.format(itemInfo.getDownScript(), params);
                    if (sourceImage != null) {
                         image = SwingFXUtils.toFXImage(sourceImage, null);
                        itemInfo.setUrl(url);
                        Image finalImage = image;
                        Platform.runLater(new Runnable() {
                            @Override
                            public void run() {
                                btnLoad.setDisable(false);
                                imgSource.setImage(finalImage);
                                processImage();
                            }
                        });
                    }
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            btnLoad.setDisable(false);
                        }
                    });
                }catch(Exception e){
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            btnLoad.setDisable(false);
                        }
                    });
                }

            }
        }).start();

    }

    public String getDefaultDownScript(){
        String data="var request=HttpUtil.createGet(url);\n" +
                "var response=request.execute();\n" +
                "ImageIO.read(response.bodyStream());";
        return data;
    }

    @FXML
    void handlerDelFilter(ActionEvent event) {
        IFilter filter=tableFilter.getSelectionModel().getSelectedItem();
        if(filter!=null) {
            tableFilter.getItems().remove(filter);
            itemInfo.getFilterList().remove(filter);
            processImage();
        }
    }

    @FXML
    void handlerDownFilter(ActionEvent event) {
        int index=tableFilter.getSelectionModel().getFocusedIndex();
        if(index<tableFilter.getItems().size()){
            IFilter moveFilter=tableFilter.getSelectionModel().getSelectedItem();
            tableFilter.getItems().remove(index);
            tableFilter.getItems().add(index+1,moveFilter);
            tableFilter.getSelectionModel().select(moveFilter);

            itemInfo.getFilterList().remove(moveFilter);
            itemInfo.getFilterList().add(index+1,moveFilter);

            processImage();
        }
    }

    @FXML
    void handlerExportFeatureLib(ActionEvent event) {
        FileChooser fileChooser = new FileChooser();
        FileChooser.ExtensionFilter extFilterFL = new FileChooser.ExtensionFilter("fl", "*.fl");
        fileChooser.getExtensionFilters().addAll(extFilterFL);
        File file = fileChooser.showSaveDialog(FxApp.primaryStage);
        try {
            FileWriter writer = new FileWriter(file);
            for(CharAspect charAspect:itemInfo.getCharAspectList()){
                writer.write(charAspect.getKey()+"|"+charAspect.getValue()+"|"+charAspect.getWidth()+"|"+charAspect.getHeight()+"\n", true);
            }
        }catch(Exception ex) {
            System.out.println(ex.getMessage());
        }
    }
    @FXML
    void handlerImportFeatureLib(ActionEvent event) {
        FileChooser fileChooser = new FileChooser();
        FileChooser.ExtensionFilter extFilterFL = new FileChooser.ExtensionFilter("fl", "*.fl");
        fileChooser.getExtensionFilters().addAll(extFilterFL);
        File file = fileChooser.showOpenDialog(FxApp.primaryStage);
        try {
            FileReader reader=new FileReader(file);
            List<String> lines=reader.readLines();
            for(String charAspectString:lines){
                String [] split=charAspectString.split("[|]");
                if(split.length>=4){
                    CharAspect charAspect=CharAspect.builder().key(split[0]).value(split[1]).width(Integer.valueOf(split[2])).height(Integer.valueOf(split[3])).build();
                    itemInfo.addCharAspect(charAspect);
                    tableFeatureLib.getItems().add(charAspect);
                }
            }
            tableFeatureLib.refresh();
        }catch(Exception ex) {
            System.out.println(ex.getMessage());
        }
    }




    @FXML
    void handlerReOcr(ActionEvent event) {
        processImage();
    }

    @FXML
    void handlerUpFilter(ActionEvent event) {
        int index=tableFilter.getSelectionModel().getFocusedIndex();
        if(index>0){
            IFilter moveFilter=tableFilter.getSelectionModel().getSelectedItem();
            tableFilter.getItems().remove(index);
            tableFilter.getItems().add(index-1,moveFilter);
            tableFilter.getSelectionModel().select(moveFilter);

            itemInfo.getFilterList().remove(moveFilter);
            itemInfo.getFilterList().add(index-1,moveFilter);

            processImage();
        }
    }

    @FXML
    void handlerLoadImage(ActionEvent event) {
        //http://login.17guagua.com/verify/v2/0.gif
        itemInfo.setUrl(txtFilePath.getText());
        loadUrlImage(txtFilePath.getText());
    }


    void processImage(){
        if(sourceImage ==null){
            return;
        }

        lblImageInfo.setText(sourceImage.getWidth()+" * " + sourceImage.getHeight());

        paneResultContainer.getChildren().clear();
        String ocrData=Cracker.cracker(itemInfo, sourceImage, chkShowOcrResult.isSelected(), chkShowOcrResult.isSelected(), new CrackerListener() {
            @Override
            public void filterFinish(BufferedImage targetBuffedImage) {
                tableFilter.refresh();

                long costTime=0;
                for(IFilter filter:itemInfo.getFilterList()){
                    if(filter.isSelected()){
                        costTime+=filter.getCostTime();
                    }
                }
                lblFilterCostTime.setText("耗时:"+formatMilliseconds(costTime));

                targetImage = ImageUtils.copyImage(targetBuffedImage);
                ScaleFilter scaleFilter=new ScaleFilter((int)(targetBuffedImage.getWidth()*scale),(int)(targetBuffedImage.getHeight()*scale));
                targetImage =scaleFilter.filter(targetBuffedImage,null);
                previewImage1=ImageUtils.copyImage(targetImage);
                if(chkShowGrid.isSelected()) {
                    ImageUtils.drawGrid(previewImage1, new Color(50, 50, 50, 10), scale);
                }
                tableFilter.refresh();
            }

            @Override
            public void splitFinish(List<SpliterInfo> splitInfolist) {
                splitInfos=splitInfolist;
                createSplitImageView(splitInfolist);
                if(chkShowSplitLine.isSelected()){
                    previewImage2=drawSplitLine();
                }

                lblOcrCostTime.setText("耗时:"+formatMilliseconds(itemInfo.getSpliter().getCostTime()));
            }
        });
        lblOcrResult.setText(ocrData!=null?ocrData.toString():"");
        showPreviewImage();
    }

    private void showPreviewImage() {
        if(previewImage2!=null) {
            imgPreview.setImage(SwingFXUtils.toFXImage(previewImage2, null));
            imgPreview.setFitWidth(previewImage2.getWidth());
            imgPreview.setFitHeight(previewImage2.getHeight());
        }
    }

    private BufferedImage drawSplitLine() {
        BufferedImage previewImage=ImageUtils.copyImage(previewImage1);
        if(chkShowSplitLine.isSelected()&&splitInfos!=null) {
            Graphics2D g = previewImage.createGraphics();
            Random random = new Random();
            for (SpliterInfo spliterInfo : splitInfos) {
                Rect rect = spliterInfo.getRect();
                g.setColor(new Color(random.nextInt(200) + 50, random.nextInt(200) + 50, random.nextInt(200) + 50));
                g.drawString(rect.getWidth()+"*"+rect.getHeight(),rect.getX() * scale, rect.getY()<5?10: rect.getY() * scale);
                g.drawRect((int)(rect.getX() * scale), (int)(rect.getY() * scale), (int)(rect.getWidth() * scale), (int)(rect.getHeight() * scale));
            }
        }
        return previewImage;
    }

    private void createSplitImageView(List<SpliterInfo> splitInfos) {
        String ocr="";
        for(SpliterInfo spliterInfo:splitInfos){
            ScaleFilter filter=new ScaleFilter(16,16);

            VBox vbox=new VBox();
            vbox.setAlignment(Pos.CENTER);
            vbox.setPrefWidth(150);
            HBox imgbox=new HBox();
            imgbox.setStyle("-fx-border-width: 1 1 0 1;-fx-border-color: #aaaaaa;");
            imgbox.setAlignment(Pos.CENTER);
            imgbox.setPrefWidth(64);
            imgbox.setPrefHeight(64);
            ImageView imageView=new ImageView(SwingFXUtils.toFXImage(spliterInfo.getFeatureImage(), null));
            imageView.setFitHeight(32);
            imageView.setFitHeight(32);

            imageView.setOnMouseClicked(new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent event) {
                    FileChooser fileChooser = new FileChooser();
                    FileChooser.ExtensionFilter extFilterJPG = new FileChooser.ExtensionFilter("png", "*.png");
                    fileChooser.getExtensionFilters().addAll(extFilterJPG);
                    File file = fileChooser.showSaveDialog(FxApp.primaryStage);
                    try {
                        BufferedImage bufferedImage=SwingFXUtils.fromFXImage(imageView.getImage(),null);
                        ImageIO.write(bufferedImage, "png", file);
                    }catch(IOException ex) {
                        System.out.println(ex.getMessage());
                    }
                }
            });
            imgbox.getChildren().add(imageView);
            vbox.getChildren().add(imgbox);

            TextField textField=new TextField();
            textField.setPromptText("请输入图片中的字符");
            textField.setAlignment(Pos.CENTER);
            textField.setText(spliterInfo.getOcrData());
            textField.setOnKeyPressed((KeyEvent E) -> {
                if(textField.getText().length()>0) {
                    BufferedImage bufferedImage = SwingFXUtils.fromFXImage(imageView.getImage(), null);
                    String ccode = Cracker.getCCode(bufferedImage);
                    CharAspect charAspect = CharAspect.builder().image(bufferedImage).key(textField.getText()).value(ccode).width(16).height(16).build();
                    if (itemInfo.addCharAspect(charAspect)) {
                        tableFeatureLib.getItems().add(charAspect);
                    }
                    tableFeatureLib.refresh();
                }
            });
            vbox.getChildren().add(textField);
            paneResultContainer.getChildren().add(vbox);
        }
    }




    @FXML
    void handlerApplyDownScriptConfig(ActionEvent event) {
        itemInfo.setDownScript(downImageScriptCode.getScript());

    }

    @FXML
    void handlerResetDownScriptConfig(ActionEvent event) {
        downImageScriptCode.setScript(getDefaultDownScript());
        itemInfo.setDownScript(getDefaultDownScript());
    }

    @FXML
    void handlerApplyOcrScriptConfig(ActionEvent event) {
        itemInfo.setOcrScript(ocrScriptCode.getScript());
    }

    @FXML
    void handlerResetOcrScriptConfig(ActionEvent event) {
        ocrScriptCode.setScript(getDefaultOcrScript());
        itemInfo.setOcrScript(getDefaultOcrScript());
    }

    @FXML
    void handlerClearFeatureLib(ActionEvent event) {
        if(FxAlerts.confirmOkCancel("确认清空","是否确认清空特征库？")){
            tableFeatureLib.getItems().clear();
            itemInfo.getCharAspectList().clear();
        }
    }

    @FXML
    void handlerZoomIn(ActionEvent event) {
        if(this.scale<=1){
            this.scale=this.scale*2;
        }else{
            this.scale+=1;
        }
        processImage();
    }
    @FXML
    void handlerZoomOut(ActionEvent event) {
        if(this.scale<=1){
            this.scale=this.scale/2;
        }else{
            this.scale-=1;
        }
        processImage();
    }

    private String getDefaultOcrScript() {
        return "result";
    }


}
